package it.a.devil;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import javax.swing.AbstractAction;
import javax.swing.DefaultListModel;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.filechooser.FileFilter;

public class Main {

	static final String SIMPLE_CONVERT = "简单转换";
	static final String SIMPLE_DECONVERT = "简单逆转换";

	static final String SURFIX_CONVERT = ".convert";

	static File sFile;

	public static void main(String[] args) throws ClassNotFoundException,
			InstantiationException, IllegalAccessException,
			UnsupportedLookAndFeelException {
		switchToWinTheme();

		final JFrame frame = new JFrame("devil");
		frame.setBounds(250, 250, 400, 300);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JList list = addFileList(frame);
		addMenu(frame, list);

		frame.setVisible(true);
	}

	// 调整成windows风格界面
	private static void switchToWinTheme() {
		String windows = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
		try {
			UIManager.setLookAndFeel(windows);
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedLookAndFeelException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	// 添加工具栏
	private static void addMenu(final JFrame frame, final JList list) {
		JMenuBar menuBar = new JMenuBar();
		// =========================================
		JMenu menuFile = new JMenu("文件");
		menuFile.setMnemonic(KeyEvent.VK_A);
		menuFile.getAccessibleContext().setAccessibleDescription(
				"The only menu in this program that has menu items");

		JMenuItem menuItemOpen = new JMenuItem("打开");
		menuItemOpen.addActionListener(new OpenFileAction(frame, list));

		JMenuItem menuItemExit = new JMenuItem("退出");
		menuItemExit.addActionListener(new ExitAppAction(frame));

		menuFile.add(menuItemOpen);
		menuFile.add(menuItemExit);
		// =========================================

		// =========================================
		ConvertAction ca = new SimpleConvertAction(list);

		JMenu menuEdit = new JMenu("编辑");
		JMenuItem menuConvertSimple = new JMenuItem(SIMPLE_CONVERT);
		menuConvertSimple.addActionListener(ca);

		menuEdit.add(menuConvertSimple);

		JMenuItem menuDeconvertSimple = new JMenuItem(SIMPLE_DECONVERT);
		menuDeconvertSimple.addActionListener(ca);

		menuEdit.add(menuConvertSimple);
		menuEdit.add(menuDeconvertSimple);
		// =========================================

		menuBar.add(menuFile);
		menuBar.add(menuEdit);
		frame.setJMenuBar(menuBar);
	}

	// 打开一个文件选择器
	private static void chooseFile(JFrame frame, JList list) {
		JFileChooser chooser = new JFileChooser();
		FileFilter fileFilter = new JavaFileFilter();
		chooser.setFileFilter(fileFilter);
		int ret = chooser.showOpenDialog(frame);
		if (ret == JFileChooser.APPROVE_OPTION) {

			DefaultListModel model = (DefaultListModel) list.getModel();
			model.removeAllElements();
			// 添加一个加入的文件
			model.addElement(chooser.getSelectedFile().getName());

			sFile = chooser.getSelectedFile();
		}
	}

	private static JList addFileList(final JFrame frame) {
		DefaultListModel listModel = new DefaultListModel();
		// listModel.addElement("Jane Doe");
		// listModel.addElement("John Smith");
		// listModel.addElement("Kathy Green");

		JList list = new JList(listModel);
		frame.add(list);
		return list;
	}

	static class OpenFileAction extends AbstractAction {

		private JFrame mFrame;
		private JList mList;

		OpenFileAction(JFrame mFrame, JList list) {
			super();
			this.mFrame = mFrame;
			this.mList = list;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			// System.out.println(e.toString());
			chooseFile(mFrame, mList);
		}
	}

	/**
	 * 退出app
	 * 
	 */
	static class ExitAppAction extends AbstractAction {

		private JFrame mFrame;

		ExitAppAction(JFrame mFrame) {
			super();
			this.mFrame = mFrame;
		}

		@Override
		public void actionPerformed(ActionEvent e) {
			int n = JOptionPane.showConfirmDialog(mFrame, "确定退出程序?", "确认",
					JOptionPane.YES_NO_OPTION);
			if (0 == n) {
				System.exit(0);
			}
		}
	}

	/**
	 * 压缩文件选择器
	 * 
	 * @author
	 * 
	 */
	static class JavaFileFilter extends javax.swing.filechooser.FileFilter {

		private List<String> mExtensions = new ArrayList<String>();

		JavaFileFilter() {
			super();
			mExtensions.add(".rar");
			mExtensions.add(".7z");
			mExtensions.add(".zip");
			mExtensions.add(".jar");
		}

		@Override
		public boolean accept(File f) {
			boolean ret = false;
			for (String e : mExtensions) {
				ret = f.getName().endsWith(e)
						|| f.getName().endsWith(e + SURFIX_CONVERT);
				if (ret) {
					return ret;
				}
			}
			return ret;
		}

		@Override
		public String getDescription() {
			return mExtensions.toString();
		}

		public void addExtension(String e) {
			mExtensions.add(e);
		}
	}

	static abstract class ConvertAction implements ActionListener {

		@Override
		public abstract void actionPerformed(ActionEvent e);

	}

	static class SimpleConvertAction extends ConvertAction {

		private final JList mList;

		SimpleConvertAction(JList mList) {
			super();
			this.mList = mList;
		}

		@Override
		public void actionPerformed(final ActionEvent e) {
			if (null != sFile) {

				new Thread(new Runnable() {

					@Override
					public void run() {
						String filename = sFile.getName();
						final String dest = sFile.getParent() + "/" + filename;
						try {
							if (e.getActionCommand().equals(SIMPLE_CONVERT)) {
								new BaseConverter(new SimpleConvert(), sFile
										.getAbsolutePath(), dest
										+ SURFIX_CONVERT).convert();
							} else if (e.getActionCommand().equals(
									SIMPLE_DECONVERT)) {
								new BaseConverter(new SimpleConvert(), sFile
										.getAbsolutePath(), dest.substring(0,
										dest.indexOf(SURFIX_CONVERT)))
										.deconvert();
							}
							SwingUtilities.invokeLater(new Runnable() {

								@Override
								public void run() {
									DefaultListModel model = (DefaultListModel) mList
											.getModel();
									model.removeAllElements();
									model.addElement(e.getActionCommand()
											+ "完成!!!");
									model.addElement("路径 " + dest);
								}
							});
						} catch (FileNotFoundException e) {
							e.printStackTrace();
						}
					}
				}).start();
			} else {
				DefaultListModel model = (DefaultListModel) mList.getModel();
				model.removeAllElements();
				model.addElement("请选择文件");
			}
		}
	}

	static interface Convert {
		int convert(byte[] data, int offset, int len, byte[] buf, int offset2,
				int len2);

		int deconvert(byte[] data, int offset, int len, byte[] buf,
				int offset2, int len2);
	}

	static abstract class BaseConvert implements Convert {
		private String mType;
		private String mpwd;

		BaseConvert(String mType, String mpwd) {
			super();
			this.mType = mType;
			this.mpwd = mpwd;
		}

		@Override
		public abstract int convert(byte[] data, int offset, int len,
				byte[] buf, int offset2, int len2);

		@Override
		public abstract int deconvert(byte[] data, int offset, int len,
				byte[] buf, int offset2, int len2);
	}

	static class BaseConverter {

		private BaseConvert mConvert;
		private String mSrc;
		private String mDest;

		BaseConverter(BaseConvert mConvert, String srcFilepath,
				String destFilepath) {
			super();
			this.mConvert = mConvert;
			this.mSrc = srcFilepath;
			this.mDest = destFilepath;
		}

		protected InputStream getInput(String filepath)
				throws FileNotFoundException {
			if (null == filepath || 0 == filepath.length()) {
				return getInput();
			} else {
				return new FileInputStream(filepath);
			}
		}

		protected InputStream getInput() {
			return null;
		}

		protected OutputStream getOutput(String filepath)
				throws FileNotFoundException {
			if (null == filepath || 0 == filepath.length()) {
				return getOutput();
			} else {
				return new FileOutputStream(filepath);
			}
		}

		protected OutputStream getOutput() {
			return null;
		}

		public void convert() throws FileNotFoundException {
			InputStream input = getInput(mSrc);
			OutputStream output = getOutput(mDest);
			assert input != null && output != null;

			byte[] buf = new byte[1024 * 8];
			byte[] data = new byte[1024];
			int len = -1;
			try {
				while (-1 != (len = input.read(data))) {
					int n = mConvert.convert(data, 0, len, buf, 0, buf.length);
					assert n >= 0 && n <= buf.length;
					output.write(buf, 0, n);
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				closeQuietly(input, output);
			}
		}

		public void deconvert() throws FileNotFoundException {
			InputStream input = getInput(mSrc);

			OutputStream output = getOutput(mDest);

			assert null != input && null != output;

			byte[] buf = new byte[1024 * 8];
			byte[] data = new byte[1024];
			int len = -1;
			try {
				while (-1 != (len = input.read(data))) {
					int n = mConvert
							.deconvert(data, 0, len, buf, 0, buf.length);
					assert n >= 0 && n <= buf.length;
					output.write(buf, 0, n);
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				closeQuietly(input, output);
			}

		}

		private void closeQuietly(Closeable... cs) {
			for (Closeable c : cs) {
				if (null != c) {
					try {
						c.close();
					} catch (IOException e) {
					}
				}
			}
		}
	}

	static class SimpleConvert extends BaseConvert {

		private Random mRand;

		SimpleConvert() {
			this("", "");
			mRand = new Random();
		}

		SimpleConvert(String mType, String mpwd) {
			super(mType, mpwd);
		}

		@Override
		public int convert(byte[] data, int offset, int len, byte[] buf,
				int offset2, int len2) {
			int j = 0;
			for (int i = 0; i < len; i++, j += 2) {
				byte b = data[offset + i];

				buf[offset2 + j] = b;
				buf[offset2 + j + 1] = (byte) mRand.nextInt();
			}
			return j;
		}

		@Override
		public int deconvert(byte[] data, int offset, int len, byte[] buf,
				int offset2, int len2) {
			int j = 0;
			for (int i = 0; i < data.length; i++) {
				byte b = data[offset + i];
				if (i % 2 == 0) {
					buf[j++] = b;
				}
			}
			return j;
		}
	}
}
